﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.DynamicData;
using System.Web.Security;
using NotAClue.ComponentModel.DataAnnotations;
using System.Web.UI.WebControls;
using System.ComponentModel.DataAnnotations;

namespace NotAClue.Web.DynamicData
{
    /// <summary>
    /// Permissions Attributes Helper Extension Methods
    /// </summary>
    public static class SecurityExtensionMethods
    {
        /// <summary>
        /// Checks to see if children columns are visible.
        /// </summary>
        /// <param name="column">The column.</param>
        /// <returns></returns>
        /// <remarks></remarks>
        public static Boolean ShowChildrenColumn(this MetaColumn column)
        {
            if (column is SecureMetaChildrenColumn && !((SecureMetaChildrenColumn)column).IsManyToMany)
            {
                var display = column.GetAttribute<DisplayAttribute>();
                if (display != null && display.GetAutoGenerateField() == true)
                    return true;
                else
                    return !(!((SecureMetaModel)column.Model).ShowChildrenColumns);
            }
            return true;
        }

        public static Boolean HasTableAction(this MetaTable table, TableActions tableAction)
        {
            // get ALL secure table attributes
            var tableRestrictions = table.Attributes.OfType<SecureTableAttribute>();
            // get user roles
            var usersRoles = Roles.GetRolesForUser();
            // set any buttons visible flag
            var anyButtonsVisible = false;
            if (tableRestrictions.Count() > 0)
            {
                foreach (var tp in tableRestrictions)
                {
                    var hasRole = tp.HasAnyRole(usersRoles);
                    if (hasRole && (tp.Actions & tableAction) == tableAction)
                        anyButtonsVisible = true;
                }
            }
            return anyButtonsVisible;
        }
        /// <summary>
        /// Finds the link button recursive.
        /// </summary>
        /// <param name="Root">The root.</param>
        /// <param name="commandName">Name of the command.</param>
        /// <returns></returns>
        /// <remarks></remarks>
        public static IButtonControl FindIButtonControlRecursive(this Control Root, string commandName)
        {
            var iButtonCtrl = Root as IButtonControl;
            if (iButtonCtrl != null && iButtonCtrl.CommandName == commandName)
                return iButtonCtrl;

            foreach (Control ctrl in Root.Controls)
            {
                var FoundCtl = FindIButtonControlRecursive(ctrl, commandName);

                if (FoundCtl != null)
                    return FoundCtl;
            }
            return null;
        }

        /// <summary>
        /// Filters the is visible.
        /// </summary>
        /// <param name="column">The column.</param>
        /// <returns>True if the filter is not expressly denied.</returns>
        public static Boolean FilterIsVisible(this MetaColumn column, PageTemplate currentPage = PageTemplate.List)
        {
            var userRoles = Roles.GetRolesForUser();
            // check to see if there are any roles
            if (userRoles.Count() > 0)
            {
                var attributes = column.Attributes;

                // using Linq to Object to get 
                // the permissions for any roles
                var permissions = from a in attributes.OfType<SecureColumnAttribute>()
                                  where a.HasAnyRole(userRoles)
                                  select a;

                foreach (var item in permissions)
                {
                    if (!item.ShowFilter)
                        return false;
                }
            }
            return true;
        }

        /// <summary>
        /// Determines whether [is filter hidden] [the specified column].
        /// </summary>
        /// <param name="column">The column.</param>
        /// <param name="currentPage">The current page.</param>
        /// <returns><c>true</c> if [is filter hidden] [the specified column]; otherwise, <c>false</c>.</returns>
        /// <remarks></remarks>
        public static Boolean IsFilterHidden(this MetaColumn column, PageTemplate currentPage)
        {
            var hideIn = column.GetAttribute<HideFilterInAttribute>();
            if (hideIn != null)
                return (hideIn.PageTemplate & currentPage) == currentPage;
            return false;
        }


        /// <summary>
        /// Secures the column visible.
        /// </summary>
        /// <param name="column">The column.</param>
        /// <returns></returns>
        public static Boolean ColumnIsVisible(this MetaColumn column)
        {
            var userRoles = Roles.GetRolesForUser();
            var activeColumnActions = column.GetColumnPermissions(userRoles);
            if (activeColumnActions.Contains(ColumnActions.DenyRead))
                return false;
            else
                return true;
        }

        /// <summary>
        /// Secures the column read only.
        /// </summary>
        /// <param name="column">The column.</param>
        /// <returns></returns>
        public static Boolean IsSecureColumnReadOnly(this MetaColumn column)
        {
            var userRoles = Roles.GetRolesForUser();
            var activeColumnActions = column.GetColumnPermissions(userRoles);
            if (activeColumnActions.Contains(ColumnActions.DenyWrite))
                return true;
            else
                return false;
        }

        /// <summary>
        /// Get a list of permissions for the specified role
        /// </summary>
        /// <param name="attributes">
        /// Is a AttributeCollection taken 
        /// from the column of a MetaTable
        /// </param>
        /// <param name="role">
        /// name of the role to be matched with
        /// </param>
        /// <returns>A List of permissions</returns>
        public static List<ColumnActions> GetColumnPermissions(this MetaColumn column, String[] roles)
        {
            var permissions = new List<ColumnActions>();

            // you could put: 
            // var attributes = column.Attributes;
            // but to make it clear what type we are using:
            System.ComponentModel.AttributeCollection attributes = column.Attributes;

            // check to see if any roles passed
            if (roles.Count() > 0)
            {
                // using Linq to Object to get 
                // the permissions for each role
                permissions = (from a in attributes.OfType<SecureColumnAttribute>()
                               where a.HasAnyRole(roles)
                               select a.Actions).ToList();
            }
            return permissions;
        }

        /// <summary>
        /// helper method to check for roles in this attribute
        /// the comparison is case insensitive
        /// </summary>
        /// <param name="roles"></param>
        /// <returns></returns>
        public static Boolean HasAnyRole(this SecureTableAttribute tablePermission, String[] roles)
        {
            var tpsRoles = tablePermission.Roles.AllToLower();
            // call extension method to convert array to lower case for compare
            foreach (var role in roles)
            {
                if (tpsRoles.Contains(role.ToLower()))
                    return true;
            }
            return false;
        }

        /// <summary>
        /// Determines whether [has any role] [the specified hidden buttons].
        /// </summary>
        /// <param name="hiddenButtons">The hidden buttons.</param>
        /// <param name="roles">The roles.</param>
        /// <returns><c>true</c> if [has any role] [the specified hidden buttons]; otherwise, <c>false</c>.</returns>
        /// <remarks></remarks>
        public static Boolean HasAnyRole(this HideSecureButtonAttribute hiddenButtons, String[] roles)
        {
            var tpsRoles = hiddenButtons.Roles.AllToLower();
            // call extension method to convert array to lower case for compare
            foreach (var role in roles)
            {
                if (tpsRoles.Contains(role.ToLower()))
                    return true;
            }
            return false;
        }

        /// <summary>
        /// helper method to check for roles in this attribute
        /// the comparison is case insensitive
        /// </summary>
        /// <param name="roles"></param>
        /// <returns></returns>
        public static Boolean HasAnyRole(this SecureColumnAttribute columnPermission, String[] roles)
        {
            var cpsRoles = columnPermission.Roles.AllToLower();
            // call extension method to convert array to lower case for compare
            foreach (var role in roles)
            {
                if (cpsRoles.Contains(role.ToLower()))
                    return true;
            }
            return false;
        }

        /// <summary>
        /// Gets the permissions.
        /// </summary>
        /// <param name="table">The table.</param>
        /// <param name="roles">The roles.</param>
        /// <returns>A list of secure table attributes</returns>
        /// <remarks></remarks>
        public static List<SecureTableAttribute> GetPermissions(this MetaTable table, String[] roles)
        {
            var tablePermissions = from sta in table.Attributes.OfType<SecureTableAttribute>()
                                   where sta.HasAnyRole(roles)
                                   select sta;

            return tablePermissions.ToList();
        }

        /// <summary>
        /// Determines whether [contains] [the specified first enum].
        /// </summary>
        /// <param name="firstEnum">The first enum.</param>
        /// <param name="secondEnum">The second enum.</param>
        /// <returns><c>true</c> if [contains] [the specified first enum]; otherwise, <c>false</c>.</returns>
        /// <remarks></remarks>
        public static Boolean Contains(this TableActions firstEnum, TableActions secondEnum)
        {
            var value = (firstEnum & secondEnum) == secondEnum;
            return value;
        }
    }
}

///// <summary>
///// Get a list of permissions for the specified role
///// </summary>
///// <param name="attributes">
///// Is a AttributeCollection taken from the column of a MetaTable
///// </param>
///// <param name="role">name of the role to be matched with</param>
///// <returns>A List of permissions</returns>
//public static List<TableActions> GetTablePermissions(this MetaTable table, String[] roles)
//{
//    var permissions = new List<TableActions>();
//    var attributes = table.Attributes;

//    // check to see if any roles passed
//    if (roles.Count() > 0)
//    {
//        // using Linq to Object to get 
//        // the permissions foreach role
//        permissions = (from a in attributes.OfType<SecureTableAttribute>()
//                       where a.HasAnyRole(roles)
//                       select a.Permission).ToList();
//    }
//    return permissions;
//}

///// <summary>
///// Get a list of permissions for the specified role
///// </summary>
///// <param name="attributes">
///// Is a AttributeCollection taken from the column of a MetaTable
///// </param>
///// <param name="role">name of the role to be matched with</param>
///// <returns>A List of permissions</returns>
//public static List<TableActions> GetFkTablePermissions(this MetaColumn column, String[] roles)
//{
//    var permissions = new List<TableActions>();
//    var foreignKeyColumn = column as MetaForeignKeyColumn;
//    var attributes = foreignKeyColumn.ParentTable.Attributes;

//    // check to see if any roles passed
//    if (roles.Count() > 0)
//    {
//        // using Linq to Object to get 
//        // the permissions foreach role
//        permissions = (from a in attributes.OfType<SecureTableAttribute>()
//                       where a.HasAnyRole(roles)
//                       select a.Permission).ToList();
//    }
//    return permissions;
//}

///// <summary>
///// Get a list of permissions for the specified role
///// </summary>
///// <param name="attributes">
///// Is a AttributeCollection taken from the column of a MetaTable
///// </param>
///// <param name="role">name of the role to be matched with</param>
///// <returns>A List of permissions</returns>
//public static List<TableActions> GetChildrenTablePermissions(this MetaColumn column, String[] roles)
//{
//    var permissions = new List<TableActions>();
//    var childrenColumn = column as MetaChildrenColumn;
//    var attributes = childrenColumn.Attributes;

//    // check to see if any roles passed
//    if (roles.Count() > 0)
//    {
//        // using Linq to Object to get 
//        // the permissions for each role
//        permissions = (from a in attributes.OfType<SecureTableAttribute>()
//                       where a.HasAnyRole(roles)
//                       select a.Permission).ToList();
//    }
//    return permissions;
//}
